package com.zhouyu.spring;


import com.zhouyu.service.AppConfig;

import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

public class ZhouyuApplicationContext {

    private Class configClass;

    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap= new ConcurrentHashMap<>();

    private ConcurrentHashMap<String, Object> singletonObject= new ConcurrentHashMap<>();
    private ArrayList<BeanPostProcessor> beanPostProcessorArrayList = new ArrayList<>();


    public ZhouyuApplicationContext(Class<AppConfig> appConfigClass) {
        this.configClass = appConfigClass;
        //扫描
        if (appConfigClass.isAnnotationPresent(ComponentScan.class)){//如果被扫描

            ComponentScan componentScanAnnotation = (ComponentScan) appConfigClass.getAnnotation(ComponentScan.class);

            String path = componentScanAnnotation.value();// 扫描路径 com.zhouyu.service

            path = path.replace(".","/");// com/zhouyu/service

            ClassLoader classLoader = ZhouyuApplicationContext.class.getClassLoader();

            URL resource = classLoader.getResource(path);

            File file = new File(resource.getFile());

            if(file.isDirectory()){
                File[] files = file.listFiles();
                for (File f : files) {
                    String fileName = f.getAbsolutePath();

                    if(fileName.endsWith(".class")){// 筛出路径下.class的文件
                        String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
                        className = className.replace("\\",".");// com.zhouyu.service.xxxx

                        try{
                            Class<?> clazz = classLoader.loadClass(className);
                            if(clazz.isAnnotationPresent(Component.class)){//是否有Componet注解

                                if(BeanPostProcessor.class.isAssignableFrom(clazz)){//是否实现了beanProcessor接口
                                    BeanPostProcessor instance = (BeanPostProcessor)clazz.newInstance();
                                    beanPostProcessorArrayList.add(instance);//加到list中
                                }
                                //Bean
                                Component component = clazz.getAnnotation(Component.class);//获取BeanName
                                String beanName = component.value();
                                if("".equals(beanName)){
                                    beanName = Introspector.decapitalize(clazz.getSimpleName());//没有值默认首字母小写
                                }

                                //生成一个BeanDefinition
                                BeanDefinition beanDefinition = new BeanDefinition();
                                beanDefinition.setType(clazz);//赋值当前类

                                if(clazz.isAnnotationPresent(Scope.class)){  //判断是否有scope注解
                                    Scope clazzAnnotation = clazz.getAnnotation(Scope.class);
                                    String scope = clazzAnnotation.value();
                                    beanDefinition.setScope(scope);// 有就设置进去
                                }else {
                                    beanDefinition.setScope("singleton");//没有就是单例
                                }

                                beanDefinitionMap.put(beanName,beanDefinition);

                            }
                        }catch (ClassNotFoundException e){
                            e.printStackTrace();
                        } catch (InstantiationException e) {
                            throw new RuntimeException(e);
                        } catch (IllegalAccessException e) {
                            throw new RuntimeException(e);
                        }

                        //如果单例 遍历beadDefinitionMap
                        for (String beanName : beanDefinitionMap.keySet()) {
                            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
                            if("singleton".equals(beanDefinition.getScope())){//如果是单例，创建个单例并放入单例map中
                                Object object = creatBean(beanName, beanDefinition);
                                singletonObject.put(beanName,object);
                            }
                        }
                    }
                }
            }
        }
    }

    private Object creatBean(String beanName, BeanDefinition beanDefinition) {
        Class clazz = beanDefinition.getType();//获取类

        try {
            Object instance = clazz.getConstructor().newInstance();//获取类的实例
            //依赖注入
            for (Field f : clazz.getDeclaredFields()) {
                if(f.isAnnotationPresent(Autowired.class)){
                    f.setAccessible(true);//??????
                    Object bean = getBean(f.getName());
                    f.set(instance,bean);//实例赋值
                }
            }

            //Aware 回调
            if(instance instanceof BeanNameAware){
                ((BeanNameAware)instance).setBeanName(beanName);
            }
            //初始化前 遍历list中的processor
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorArrayList) {
                beanPostProcessor.postProcessBeforeInitialization(beanName,instance);
            }
            //初始化
            if(instance instanceof InitializingBean){
                ((InitializingBean)instance).afterPropertiesSet();
            }
            //初始化后 AOP BeanPostProcessor
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorArrayList) {
                beanPostProcessor.postProcessAfterInitialization(beanName,instance);
            }

            return instance;
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    public Object getBean(String beanName){

        //有，map的value就是beanDefinition
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if(beanDefinition == null){
            throw new RuntimeException("bean not found in beanDefinition exception:"+beanName);//没有，抛异常
        }else {
            String scope = beanDefinition.getScope();//获取作用域

            if("singleton".equals(scope)){
                Object  bean = singletonObject.get(beanName);
                if(bean == null){
                    Object o = creatBean(beanName, beanDefinition);
                    singletonObject.put(beanName,o);
                }
                return bean;
            }else {
                return creatBean(beanName,beanDefinition);//多例
            }
        }
        //主分支写的代码
    }


}
